package org.seed.mybatis.springboot.spi;

import lombok.extern.slf4j.Slf4j;
import org.seed.mybatis.core.ext.MapperRunner;
import org.seed.mybatis.core.ext.spi.MapperBuilder;
import org.seed.mybatis.springboot.MapperDatasourceMapContext;
import org.seed.mybatis.springboot.scatter.DataSourceContext;
import org.seed.mybatis.springboot.scatter.ScatterInfo;
import org.seed.mybatis.springboot.scatter.ShardingStrategy;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;


@Slf4j
public class SpringContextMapperBuilder implements MapperBuilder {

    private static final Map<String, MapperRunner> runnerMap = new HashMap<>();

    @Override
    public <T> MapperRunner<T> getMapperRunner(Class<T> mapperClass, ApplicationContext applicationContext) {
        String simpleName = mapperClass.getSimpleName();
        simpleName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
        // 是否有分库分表配置
        ScatterInfo scatterInfo = MapperDatasourceMapContext.getScatterInfo(simpleName);
        MapperRunner<T> cached = null;
        if (scatterInfo == null) {
            cached = runnerMap.get(simpleName);
            String datasourceName = MapperDatasourceMapContext.getDatasourceName(simpleName);
            if (StringUtils.hasText(datasourceName)) {
                DataSourceContext.setDataSourceKey(datasourceName);
                log.debug("\uD83D\uDCA7 {} 正在使用数据源: {}", simpleName, datasourceName);
            }
        } else {
            ShardingStrategy shardingStrategy = scatterInfo.getShardingStrategy();
            DataSourceContext.setDataSourceKey(shardingStrategy.getDataSourceId());
        }
        if (cached != null) {
            log.debug("Using cached bean object: {}", simpleName);
            return cached;
        }
        T mapper = (T)applicationContext.getBean(simpleName);
        MapperRunner<T> rst = new MapperRunner<T>(mapper);
        if (scatterInfo == null) {
            runnerMap.put(simpleName, rst);
        }
        return rst;

    }
}